package com.free4inno.knowledgems.openapi;

import com.alibaba.fastjson.JSON;
import com.free4inno.knowledgems.dao.GroupInfoDao;
import com.free4inno.knowledgems.dao.LabelInfoDao;
import com.free4inno.knowledgems.dao.UserDao;
import com.free4inno.knowledgems.domain.GroupInfo;
import com.free4inno.knowledgems.domain.LabelInfo;
import com.free4inno.knowledgems.domain.ResourceES;
import com.free4inno.knowledgems.domain.User;
import com.free4inno.knowledgems.service.ResourceEsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.*;

/**
 * Author HUYUZHU.
 * Date 2021/10/24 16:58.
 * Open API
 * TODO 接口已做统一返回处理，返回的数据类型不可为String，以免与Spring机制产生BUG。如有需要返回String格式的data，请调用Result的静态方法封装到Result<String>中返回！
 */

@Slf4j
@RestController
@RequestMapping("openapi")
@Validated
public class OpenAPIController {

    @Autowired
    private GroupInfoDao groupInfoDao;

    @Autowired
    private LabelInfoDao labelInfoDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private ResourceEsService resourceEsService;

    @GetMapping("demo")
    public Result<String> demoApi(
            @RequestParam(required = true, value = "testparam") @NotBlank String testparam) {
        return Result.success(testparam);
    }

    @GetMapping("search")
    public Map<String, Object> search(
            @RequestParam(required = true, value = "pageNum") @NotNull @Min(1) Integer pageNum,
            @RequestParam(required = true, value = "pageSize") @NotNull @Min(1) Integer pageSize,
            @RequestParam(required = true, value = "queryStr") String queryStr,
            @RequestParam(required = true, value = "groupNames") @NotBlank String groupNames,
            @RequestParam(required = true, value = "labelNames") @NotBlank String labelNames) {
        Map<String, Object> jsonObject = new HashMap<>();

        // ============================== 检验参数 ==============================
        List<String> searchGroups = new ArrayList<>();
        List<String> searchLabels = new ArrayList<>();
        try {
            // 群组，标签：以汉字JSONArray格式传入，首先校验并转换格式
            searchGroups = JSON.parseArray(groupNames, String.class);
            searchLabels = JSON.parseArray(labelNames, String.class);
        } catch (Exception e) {
            throw new OpenAPIException(ResultEnum.ARGS_ERROR);
        }
        ArrayList<String> groupIds = new ArrayList<>();
        ArrayList<String> labelIds = new ArrayList<>();
        for (String groupName : searchGroups) {
            // 群组：检查是否在标签列表中有对应id，不存在则报错
            GroupInfo groupInfo = groupInfoDao.findByGroupName(groupName).orElse(new GroupInfo());
            if (groupInfo.getId() != null) {
                groupIds.add(groupInfo.getId().toString());
            } else {
                throw new OpenAPIException(ResultEnum.ARGS_ERROR);
            }
        }
        for (String labelName : searchLabels) {
            // 标签：检查是否在标签列表中有对应id，不存在则报错
            LabelInfo labelInfo = labelInfoDao.findByLabelName(labelName).orElse(new LabelInfo());
            if (labelInfo.getId() != null && labelInfo.getUplevelId() != 0) {
                labelIds.add(labelInfo.getId().toString());
            } else {
                throw new OpenAPIException(ResultEnum.ARGS_ERROR);
            }
        }

        // ============================== 业务处理 ==============================
        try {
            // 2. 调用 ResourceEsService 进行搜索 -----------
            Page<ResourceES> resourceESPage = resourceEsService.searchResourceES(pageNum - 1, pageSize, queryStr, groupIds, labelIds, 1, true);

            // 3. 构建返回 ---------------------------------

            // 结果资源总数 & 总页数
            long totalResources = resourceESPage.getTotalElements();
            long totalPages;
            if (totalResources % pageSize == 0) {
                totalPages = totalResources / pageSize;
            } else {
                totalPages = totalResources / pageSize + 1;
            }

            // 遍历搜索结果获取搜索结果列表中展示的标题、正文、作者名、群组名、标签名等信息
            List<ResourceES> resourceESList = resourceESPage.getContent();

            // 3.1. build 3 hash set to De-duplication : author, label, group
            HashSet<Integer> usersId = new HashSet<>();
            HashSet<Integer> labelsId = new HashSet<>();
            HashSet<Integer> groupsId = new HashSet<>();
            for (ResourceES resourceES : resourceESList) {
                // 3.1.1. author
                if (resourceES.getUser_id() != null) {
                    int userId = resourceES.getUser_id();
                    usersId.add(userId);
                }
                // 3.1.2. label
                if (resourceES.getLabel_id() != null && !resourceES.getLabel_id().equals("")) {
                    String[] label = resourceES.getLabel_id().split(",|，");
                    for (String s : label) {
                        int labelId = (s == "" ? 0 : Integer.parseInt(s));
                        labelsId.add(labelId);
                    }
                }
                // 3.1.3. group
                if (resourceES.getGroup_id() != null && !resourceES.getGroup_id().equals("")) {
                    String[] group = resourceES.getGroup_id().split(",|，");
                    for (String s : group) {
                        int groupId = (s == "" ? 0 : Integer.parseInt(s));
                        groupsId.add(groupId);
                    }
                }
            }

            // 3.2. build 3 hash map to save all string names
            HashMap<Integer, String> usersName = new HashMap<>();
            HashMap<Integer, String> labelsName = new HashMap<>();
            HashMap<Integer, String> groupsName = new HashMap<>();
            // 3.2.1. author
            for (Integer userId : usersId) {
                User user = userDao.findById(userId).orElse(new User());
                if (user.getRealName() != null) {
                    usersName.put(userId, user.getRealName());
                } else {
                    usersName.put(userId, "自邮之翼" + userId);
                }
            }
            // 3.2.2. label
            for (Integer labelId : labelsId) {
                LabelInfo labelInfo = labelInfoDao.findById(labelId).orElse(new LabelInfo());
                if (labelInfo.getLabelName() != null) {
                    String ln = labelInfo.getLabelName();
                    labelsName.put(labelId, ln);
                } else {
                    labelsName.put(labelId, "未知标签" + labelId);
                }
            }
            // 3.2.3. group
            for (Integer groupId : groupsId) {
                GroupInfo groupInfo = groupInfoDao.findById(groupId).orElse(new GroupInfo());
                if (groupInfo.getGroupName() != null) {
                    String gn = groupInfo.getGroupName();
                    groupsName.put(groupId, gn);
                } else {
                    groupsName.put(groupId, "未知群组" + groupId);
                }
            }

            // 3.3. use names in map, reduce interactions with DB
            for (ResourceES resourceES : resourceESList) {
                String text = resourceES.getText().replaceAll("<.*?>", "");
                String title = resourceES.getTitle();
                resourceES.setText(text.length() > 100 ? text.substring(0, 100) + "... ..." : text);
                resourceES.setTitle(title.replaceAll("<.*?>", ""));
                // 取作者名
                if (resourceES.getUser_id() != null) {
                    int userId = resourceES.getUser_id();
                    resourceES.setUser_name(usersName.get(userId));
                }
                // 取群组名
                String groupName = "";
                if (resourceES.getGroup_id() != null && !resourceES.getGroup_id().equals("")) {
                    String[] group = resourceES.getGroup_id().split(",|，");
                    for (String s : group) {
                        int groupId = (s == "" ? 0 : Integer.parseInt(s));
                        groupName = groupName + "," + groupsName.get(groupId);
                    }
                    groupName = groupName.substring(1);
                } else {
                    groupName = "该资源无群组";
                }
                resourceES.setGroup_name(groupName);
                // 取标签名
                String labelName = "";
                if (resourceES.getLabel_id() != null && !resourceES.getLabel_id().equals("")) {
                    String[] label = resourceES.getLabel_id().split(",|，");
                    for (String s : label) {
                        int labelId = (s == "" ? 0 : Integer.parseInt(s));
                        labelName = labelName + "," + labelsName.get(labelId);
                    }
                    labelName = labelName.substring(1);
                } else {
                    labelName = "该资源无标签";
                }
                resourceES.setLabel_name(labelName);
            }

            // 查询信息
            jsonObject.put("queryStr", queryStr);
            jsonObject.put("groupNames", searchGroups);
            jsonObject.put("labelNames", searchLabels);
            // 分页信息
            jsonObject.put("pageNum", pageNum);
            jsonObject.put("pageSize", pageSize);
            jsonObject.put("totalPages", totalPages);
            jsonObject.put("totalResources", totalResources);
            // 资源信息
            jsonObject.put("resource", resourceESList);

        } catch (Exception e) {
            throw new OpenAPIException(ResultEnum.WORK_ERROR);
        }

        return jsonObject;
    }

}
